
/*
 * 06.05.2007 niXman, i dot nixman at gmail dot com
 * UP 10.02.2009
 * UP 24.07.2009
 * UP 25.07.2009
 * UP 06.11.2009
 * UP 01.05.2011
 * UP 22.12.2011
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA.
 *
 */

#ifndef _mfio_h_included_
#define _mfio_h_included_

#include <sys/types.h>
#include <stdio.h>

#define SILENT (1)

#ifdef __cplusplus
namespace mfio {
#endif

/****************************************************************************/

#ifdef _WIN32

#include <windows.h>
typedef CRITICAL_SECTION mfio_mutex_type;

#define mfio_mutex_init(mutex) InitializeCriticalSection(mutex)
#define mfio_mutex_destroy(mutex) DeleteCriticalSection(mutex)
#define mfio_mutex_lock(mutex) EnterCriticalSection(mutex)
#define mfio_mutex_trylock(mutex) TryEnterCriticalSection(mutex)
#define mfio_mutex_unlock(mutex) LeaveCriticalSection(mutex)

#else

#include <pthread.h>
typedef pthread_mutex_t mfio_mutex_type;

#define mfio_mutex_init(mutex) pthread_mutex_init(mutex, 0)
#define mfio_mutex_destroy(mutex) pthread_mutex_destroy(mutex)
#define mfio_mutex_lock(mutex) pthread_mutex_lock(mutex)
#define mfio_mutex_trylock(mutex) pthread_mutex_trylock(mutex)
#define mfio_mutex_unlock(mutex) pthread_mutex_unlock(mutex)

#endif // _WIN32

/****************************************************************************/

/** macroses for struct FILE for any platform */
#if (defined(__GNUC__) || defined(__LCC__) || defined(_MSC_VER)) && defined(_WIN32)
#  define MFIO_FH(f) ((file_header*)f->_ptr)
#  define MFIO_FP(f) (f->_ptr)
#elif defined(__GNUC__) && !defined(_WIN32)
#  define MFIO_FH(fh) ((file_header*)fh->_IO_read_ptr)
#  define MFIO_FP(fh) (fh->_IO_read_ptr)
#else
#  define MFIO_FH(fh) ((file_header*)fh->buffer)
#  define MFIO_FP(fh) (fh->buffer)
#endif

/** debug macross */
#if !defined(SILENT)
#	define MFIO_MSG(text) fprintf(stdout, "msg %s:%d message: %s\n", __FILE__, __LINE__, (#text))
#	define MFIO_DEB(exp) fprintf(stderr, "In file %s:%d expression: (%s) %s\n", __FILE__, __LINE__, (#exp), (exp)?"succeeded!":"failure!")
#	define MFIO_DEBRET(exp, val) DEB(exp); if ( !(exp)) return (val)
#	define MFIO_DEBBRK(exp) DEB(exp); if ( !(exp)) return
#else
#	define MFIO_MSG(text)
#	define MFIO_DEB(exp) (exp)
#	define MFIO_DEBRET(exp, val) if ( !(exp) ) return (val)
#	define MFIO_DEBBRK(exp) if ( !(exp) ) return
#endif

/** zeroes the POD type pointed to by the `exp` */
#define ZEROPOD(exp) memset(exp, 0, sizeof(*exp))

/****************************************************************************/

/** struct ONLY for internal uses */
typedef struct _file_header {
   char*					arr;
   char*					name;
   char					mode;
   char					is_mfio[2];
   u_int32_t         arr_size;
   u_int32_t			index;
   mfio_mutex_type	mutex;
} file_header;

/****************************************************************************/

/* ONLY FOR INTERNAL USE!
 * initialize internal struct `file_header`
 * \fn init
 * \a name of the file
 * \a mode of the file
 * \ret if succeeded returns the pointer to the allocated,
 * otherwise return the NULL
 */
file_header* init(
   const char* name,
   const char* mode
);

/* ONLY FOR INTERNAL USE!
 * deinitialize internal struct `file_header`
 * and free allocated memory
 * \fn clean
 * \a internal_file the pointer to the internal strict `file_header`
 * \ret no returns
 */
void clean(
   file_header* internal_file
);

FILE* mfopen(
   const char* name,
   const char* mode
);

int mfclose(
   FILE* mfio_file
);

int mfeof(
   FILE* mfio_file
);

int mfputc(
   char ch,
   FILE* mfio_file
);

int mfputs(
   const char* str,
   FILE* mfio_file
);

int mfgetc(
   FILE* mfio_file
);

char* mfgets(
   char* buff,
   int max,
   FILE* mfio_file
);

int mungetc(
   int ch,
   FILE* mfio_file
);

int mfseek(
   FILE* mfio_file,
   long offset,
   int direction
);

long mftell(
   FILE* mfio_file
);

int mfwrite(
   const void* buffer,
   size_t item_size,
   size_t items_count,
   FILE* mfio_file
);

int mfread(
   void* buffer,
   size_t item_size,
   size_t items_count,
   FILE* mfio_file
);

/** Hack... ****************************************************************/

int is_mfio_file(
   FILE* file
);

int is_real_file(
   FILE* file
);

/* check for `mfio_file` in read mode
 * \fn is_readable
 * \a mfio_file pointer to the file
 * \ret 1 if is readable, otherwise 0
 */
int is_readable(
   FILE* mfio_file
);

/* check for `mfio_file` in write mode
 * \fn is_writable
 * \a mfio_file pointer to the file
 * \ret 1 if is writable, otherwise 0
 */
int is_writable(
   FILE* mfio_file
);

FILE*	load_from_file(
   const char* real_file_name
);

int save_to_file(
   const char* real_file_name,
   FILE* mfio_file
);

void set_mode(
   const char* new_mode,
   FILE* mfio_file
);

void set_writable(
   FILE* mfio_file
);

void set_readable(
   FILE* mfio_file
);

char* get_buffer(
   FILE* mfio_file
);

u_int32_t get_buffer_size(
   FILE* mfio_file
);

char* set_buffer(
   FILE* mfio_file,
   char* buffer,
   int buffer_size
);

int resize(
   FILE* mfio_file,
   u_int32_t new_size
);

int truncate(
   FILE* mfio_file
);

int cat_file(
   FILE* mfio_file1,
   FILE* mfio_file2
);

int cat_file2(
   FILE* mfio_file,
   const char* real_file_name
);

void report(
   FILE* mfio_file
);

char* get_name(
   FILE* mfio_file
);

char* get_mode(
   FILE* mfio_file
);

/****************************************************************************/

#ifdef __cplusplus
} // namespace mfio
#endif

#endif /** _mfio_h_included_ */

